﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Security.Principal;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using System.Web.Routing;
using System.Web.Script.Serialization;
using System.Web.Security;
using System.Web.WebPages;
//using CodeSmith.Data.Caching;
namespace System.Web.Mvc
{
	public enum LabelPostion { None = 1, Before = 2, After = 4 }
}


/// <summary>The SectionExtensions class</summary>
/// <remarks>http://blogs.msdn.com/b/marcinon/archive/2010/12/08/optional-razor-sections-with-default-content.aspx</remarks>
/// <seealso>http://blogs.msdn.com/b/marcinon/archive/2010/12/15/razor-nested-layouts-and-redefined-sections.aspx</seealso>
/// <created author="laurentiu.macovei" date="Sat, 08 Jan 2011 23:22:45 GMT"/>
public static class SectionExtensions
{

	#region Fields


	#region Const

	private static readonly object _o = new object();
	private static readonly HelperResult EmptyContent = new HelperResult(_ => { });

	#endregion Const


	#region Static

	static HelperResult Empty = new HelperResult(_ => { });
	private static PropertyInfo PreviousSectionWriters = typeof(WebPageBase).GetProperty("PreviousSectionWriters", BindingFlags.Instance | BindingFlags.NonPublic);
	private static PropertyInfo SectionWritersStack = typeof(WebPageBase).GetProperty("SectionWritersStack", BindingFlags.Instance | BindingFlags.NonPublic);

	#endregion Static


	#endregion Fields


	#region Util Methods

	/// <summary>
	/// </summary>
	/// <param name="page"></param>
	/// <returns></returns>
	/// <created author="laurentiu.macovei" date="Fri, 18 Mar 2011 02:23:32 GMT"/>
	private static Dictionary<string, SectionWriter> GetPreviousWriters(this WebPageBase page)
	{
		var sections = (Dictionary<string, SectionWriter>)PreviousSectionWriters.GetValue(page, null);
		return sections;
	}

	/// <summary>
	/// </summary>
	/// <param name="page"></param>
	/// <returns></returns>
	/// <created author="laurentiu.macovei" date="Fri, 18 Mar 2011 02:23:32 GMT"/>
	private static Stack<Dictionary<string, SectionWriter>> GetSectionWritersStack(this WebPageBase page)
	{
		var sections = (Stack<Dictionary<string, SectionWriter>>)SectionWritersStack.GetValue(page, null);
		return sections;
	}


	#endregion Util Methods


	#region Business Methods
	/// <summary>Returns whether the given type allows null value</summary>
	/// <param name="type"></param>
	/// <returns></returns>
	/// <created author="laurentiu.macovei" date="Sat, 26 Mar 2011 23:44:08 GMT"/>
	public static bool TypeAllowsNullValue(this Type type)
	{
		return type != null && (!type.IsValueType || Nullable.GetUnderlyingType(type) != null);
	}
	/// <summary>
	/// </summary>
	/// <param name="writer"></param>
	/// <param name="value"></param>
	/// <returns></returns>
	/// <created author="laurentiu.macovei" date="Sat, 11 Feb 2012 02:56:31 GMT"/>
	public static TextWriter Append(this TextWriter writer, dynamic value)
	{
		writer.Write(value);
		return writer;
	}

	/// <summary>Renders radio buttons for all (filtered) values of a given Enum</summary>
	/// <param name="htmlHelper">The HTML helper instance that this method extends.</param>
	/// <param name="expression"></param>
	/// <param name="beginTag">The tag to render the options in. i.e. "ul" to render the questions in an &lt;ul&gt; tag. Defaults to "ul"</param>
	/// <param name="itemTag">The tag to render each option in. i.e. "li" to render each question in a &lt;li&gt; tag</param>
	/// <param name="separator">The separator text to be rendered between two options. Defaults to "&amp;nbsp;" (a visible whitespace)</param>
	/// <param name="filterEnums">A func to filter which enum values to be rendered. Return false to exclude those you don't want</param>
	/// <param name="labelPosition">Where to render the label text. Select None so no label will be rendered at all</param>
	/// <param name="htmlAttributes">An object that contains the HTML attributes to set for each radio button element.</param>
	/// <param name="renderRadioButtons">Specify false if you don't want the radio buttons to be rendered i.e. you need only the labels. Defaults to true</param>
	/// <param name="labelsAsText">Specify false means that lables text will be rendered within a &lt;label for="model"&gt; tag. Specify true if you need a simple text. Defaults to false</param>
	/// <param name="labelAttributes">Specify custom attributes to the label of each of the rendered items</param>
	/// <param name="itemAttributes">An object that contains the HTML attributes to set for each item element i.e. li.</param>
	/// <param name="skipValues">How many items to be skipped. Defaults to 1 i.e. NotSet value</param>
	/// <param name="beginTagAttributes">Custom html attributes when beginTag is specified</param>
	/// <param name="itemsPerRow">Specify how many items per row should be displayed. Defaults to null, which means no rows will be created. If beginTag is div it will be replaced as table and if itemTag is null it will be replaced as td. RowTag already defaults to tr.</param>
	/// <param name="itemAction">A custom action that is executed before each item is rendered. Parameters are: index, value, writer</param>
	/// <param name="printLegend">Specify whether to print a &lt;legend&gt; tag after the beginTag. Useful when rendering beginTag as fieldset</param>
	/// <param name="rowTag">Specify the tag to be used then itemsPerRow is provided, hence rendering on multiple rows. Defaults to tr</param>
	/// <created author="laurentiu.macovei" date="Fri, 18 Mar 2011 19:54:13 GMT"/>
	public static HelperResult RadioButtonsFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper,
		Expression<Func<TModel, TProperty>> expression,
		object htmlAttributes = null, Func<TProperty, bool> filterEnums = null,
		LabelPostion labelPosition = LabelPostion.After, string separator = "&nbsp;",
		string beginTag = "ul", string itemTag = "li", bool renderRadioButtons = true,
		bool labelsAsText = false, object labelAttributes = null, int? itemsPerRow = null,
		string rowTag = "tr", object beginTagAttributes = null, object itemAttributes = null,
		bool printLegend = false, Action<int, TProperty, TextWriter> itemAction = null,
		int skipValues = 1)
		where TProperty : IConvertible
	{
		return RenderEnum<TModel, TProperty>(htmlHelper, expression,
			(html, metadata, htmlFieldId) => htmlFieldId,
			(html, index, htmlFieldName, htmlFieldId, item, value, dicAttributes, writer)
				=>
			{
				//if (index == 0)
				{
					//first time annulate HtmlFieldPrefix to avoid duplicate names when used from templates i.e. Gender.Gender[]
					var templateInfo = html.ViewContext.ViewData.TemplateInfo;
					var htmlFieldPrefix = templateInfo.HtmlFieldPrefix;
					//if (templateInfo.HtmlFieldPrefix == htmlFieldId)
					templateInfo.HtmlFieldPrefix = null;
				}
				writer.Write(htmlHelper.RadioButton(htmlFieldName, item.ToInt64(CultureInfo.InvariantCulture), item.Equals(value), dicAttributes).ToString());
			},
			htmlAttributes, filterEnums, labelPosition, separator, beginTag, itemTag, renderRadioButtons, labelsAsText,
			labelAttributes, itemsPerRow, rowTag, beginTagAttributes, itemAttributes, printLegend, itemAction, skipValues);
	}

	/// <summary>Renders radio buttons for all (filtered) values of a given Enum</summary>
	/// <param name="htmlHelper">The HTML helper instance that this method extends.</param>
	/// <param name="expression"></param>
	/// <param name="beginTag">The tag to render the options in. i.e. "ul" to render the questions in an &lt;ul&gt; tag. Defaults to "ul"</param>
	/// <param name="itemTag">The tag to render each option in. i.e. "li" to render each question in a &lt;li&gt; tag</param>
	/// <param name="separator">The separator text to be rendered between two options. Defaults to "&amp;nbsp" (a visible whitespace)</param>
	/// <param name="filterEnums">A func to filter which enum values to be rendered. Return false to exclude those you don't want</param>
	/// <param name="labelPosition">Where to render the label text. Select None so no label will be rendered at all</param>
	/// <param name="htmlAttributes">An object that contains the HTML attributes to set for each radio button element.</param>
	/// <param name="itemAttributes">An object that contains the HTML attributes to set for each item element i.e. li.</param>
	/// <param name="renderCheckBoxes">Specify false if you don't want the check buttons to be rendered i.e. you need only the labels. Defaults to true</param>
	/// <param name="skipValues">How many items to be skipped. Defaults to 1 i.e. NotSet value</param>
	/// <param name="printLegend">Specify whether to print a &lt;legend&gt; tag after the beginTag. Useful when rendering beginTag as fieldset</param>
	/// <param name="itemAction">A custom action that is executed before each item is rendered. Parameters are: index, value, writer</param>
	/// <param name="rowTag">Specify the tag to be used then itemsPerRow is provided, hence rendering on multiple rows. Defaults to tr</param>
	/// <param name="beginTagAttributes">Custom html attributes when beginTag is specified</param>
	/// <param name="labelsAsText">Specify false means that lables text will be rendered within a &lt;label for="model"&gt; tag. Specify true if you need a simple text. Defaults to false</param>
	/// <param name="labelAttributes">Specify custom attributes to the label of each of the rendered items</param>
	/// <param name="itemsPerRow">Specify how many items per row should be displayed. Defaults to null, which means no rows will be created. If beginTag is div it will be replaced as table and if itemTag is null it will be replaced as td. RowTag already defaults to tr.</param>
	/// <created author="laurentiu.macovei" date="Fri, 18 Mar 2011 19:54:13 GMT"/>
	public static HelperResult CheckBoxesFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes = null, Func<TProperty, bool> filterEnums = null,
		LabelPostion labelPosition = LabelPostion.After, string separator = "&nbsp;",
		string beginTag = "ul", string itemTag = "li", bool renderCheckBoxes = true,
		bool labelsAsText = false, object labelAttributes = null, int? itemsPerRow = null,
		string rowTag = "tr", object beginTagAttributes = null, object itemAttributes = null,
		bool printLegend = false, Action<int, TProperty, TextWriter> itemAction = null,
		int skipValues = 1)
		where TProperty : IConvertible
	{
		return RenderEnum<TModel, TProperty>(htmlHelper, expression,
			(html, metadata, htmlFieldId) => htmlFieldId + "[]",
			(html, index, htmlFieldName, htmlFieldId, item, value, dicAttributes, writer) =>
			{
				if (index == 0)
				{
					//first time annulate HtmlFieldPrefix to avoid duplicate names when used from templates i.e. Gender.Gender[]
					var templateInfo = html.ViewContext.ViewData.TemplateInfo;
					var htmlFieldPrefix = templateInfo.HtmlFieldPrefix;
					if (templateInfo.HtmlFieldPrefix == htmlFieldId)
						templateInfo.HtmlFieldPrefix = null;
				}
				dicAttributes["value"] = item.ToInt64(CultureInfo.InvariantCulture);
				writer.Write(html.CheckBox(htmlFieldName, (bool)(((dynamic)value & (dynamic)item) != 0), dicAttributes).ToString()
					.Replace(CheckBox_Value_ValueFalse, CheckBox_Value_NotSet));
				//templateInfo.HtmlFieldPrefix = htmlFieldId;//restore the htmlFieldPrefix to the previous value, so it won't get altered in e.g LabelFor afterwards
			},
			htmlAttributes, filterEnums, labelPosition, separator, beginTag, itemTag, renderCheckBoxes, labelsAsText,
			labelAttributes, itemsPerRow, rowTag, beginTagAttributes, itemAttributes, printLegend, itemAction, skipValues);
		/*return new HelperResult(sb =>
		{
			var labelsBefore = labelPositon == LabelPostion.Before;
			var labelsAfter = labelPositon == LabelPostion.After;
			var htmlFieldId = ExpressionHelper.GetExpressionText(expression);
			ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
			dynamic value = (TProperty)(metadata.Model ?? (metadata.ModelType.IsValueType ? (dynamic)default(TProperty) : null));
			htmlFieldId = TagBuilder.CreateSanitizedId(htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(htmlFieldId));
			var htmlFieldName = htmlFieldId + "[]";
			var dicAttributes = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
			if (!dicAttributes.ContainsKey("class"))
				dicAttributes.Add("class", "radio");
			var dicBeginTagAttributes = beginTagAttributes as RouteValueDictionary;
			dicBeginTagAttributes = dicBeginTagAttributes ?? (beginTagAttributes == null ? null : HtmlHelper.AnonymousObjectToHtmlAttributes(beginTagAttributes));

			if (itemsPerRow.HasValue)
			{
				if (beginTag == "div")
					beginTag = "table";
				if (itemTag == null)
					itemTag = "td";
			}
			TagBuilder beginTagBuilder = null, rowBuilder = null;
			if (!string.IsNullOrWhiteSpace(beginTag))
			{
				beginTagBuilder = new TagBuilder(beginTag);
				if (dicBeginTagAttributes != null)
					beginTagBuilder.MergeAttributes(dicBeginTagAttributes);
				beginTagBuilder.MergeAttribute("class", "formee-list " + htmlFieldName, false);
				sb.Append(beginTagBuilder.ToString(TagRenderMode.StartTag));
			}
			if (itemsPerRow.HasValue && !string.IsNullOrEmpty(rowTag))
				rowBuilder = new TagBuilder(rowTag);


			var insertSeparator = false;
			var enums = (IEnumerable<TProperty>)Enum.GetValues(typeof(TProperty));
			//var NotSet = "value=\""+((TProperty)(IConvertible)0).ToString()+"\"";
			var NotSet = "value=\"\"";
			var ValueFalse = "value=\"false\"";
			int index = 0;
			foreach (TProperty item in enums.Cast<TProperty>().Skip(skipValues))
				if (filterEnums == null || filterEnums(item))
				{
					if (itemAction != null)
						itemAction(index, item, sb);
					TagBuilder itemBuilder = null;
					if (itemsPerRow.HasValue && !string.IsNullOrEmpty(rowTag))
					{
						if (index != 0 && index % itemsPerRow.Value == 0)
							sb.Append(rowBuilder.ToString(TagRenderMode.EndTag));
						if (index % itemsPerRow.Value == 0)
						{
							rowBuilder.Attributes["class"] = "row" + index / itemsPerRow.Value;
							sb.Append(rowBuilder.ToString(TagRenderMode.StartTag));
						}
						//if (index != 0 && index % itemsPerRow.Value == 0)
						//    sb.Append("</").Append(rowTag).Append(">");
						//if (index % itemsPerRow.Value == 0)
						//    sb.Append("<").Append(rowTag).Append(" class='row").Append(index / itemsPerRow.Value).Append("'>");
						index++;
					}
					var fieldName = htmlFieldId + "_" + item.ToString();
					dicAttributes["id"] = fieldName;
					if (!string.IsNullOrWhiteSpace(itemTag))
					{
						itemBuilder = new TagBuilder(itemTag);
						var attrs = itemAttributes == null ? null : HtmlHelper.AnonymousObjectToHtmlAttributes(itemAttributes);
						var @class = fieldName;
						if (attrs != null)
						{
							@class = attrs["class"] as string;
							@class = string.IsNullOrWhiteSpace(@class) ? fieldName : fieldName + " " + @class;
						}
						itemBuilder.MergeAttributes(attrs);
						itemBuilder.Attributes["class"] = @class;
						sb.Append(itemBuilder.ToString(TagRenderMode.StartTag));
					}
					else if (insertSeparator)
					{
						sb.Append(separator);
					}
					else insertSeparator = true;
					string labelText = null;
					bool isHtmlLabel = false;
					if (labelPositon != LabelPostion.None)
					{
						var labelHtml = item.AsHtmlString();
						if (labelHtml is IHtmlString)
						{
							labelText = ((IHtmlString)labelHtml).ToHtmlString();
							isHtmlLabel = true;
						}
						else labelText = (labelHtml ?? string.Empty).ToString();
					}
					if (labelsBefore)
						sb.Append(htmlHelper.Label(fieldName, labelText, html: isHtmlLabel).ToHtmlString());
					dynamic itemValue = item;
					dicAttributes["value"] = itemValue;
					sb.Append(htmlHelper
						.CheckBox(htmlFieldName, (bool)((value & itemValue) != 0), dicAttributes)
						.ToHtmlString()
						.Replace(ValueFalse, NotSet))
						;
					if (labelsAfter)
						sb.Append(htmlHelper.Label(fieldName, labelText, html: isHtmlLabel).ToHtmlString());
					if (itemBuilder != null)
						sb.Append(itemBuilder.ToString(TagRenderMode.EndTag));
				}
			//if (itemsPerRow.HasValue && index % itemsPerRow.Value != 0 && !string.IsNullOrEmpty(rowTag))
			//    sb.Append("</").Append(rowTag).Append(">");
			if (index != 0 && rowTag != null)
				sb.Append(rowBuilder.ToString(TagRenderMode.EndTag));
			//if (itemsPerRow.HasValue && index % itemsPerRow.Value != 0 && !string.IsNullOrEmpty(rowTag))
			//    sb.Append("</").Append(rowTag).Append(">");
			if (beginTagBuilder != null)
				sb.Append(beginTagBuilder.ToString(TagRenderMode.EndTag));
		});*/
	}


	/// <summary>
	/// </summary>
	/// <param name="htmlHelper"></param>
	/// <param name="expression"></param>
	/// <param name="buildHtmlFieldName"></param>
	/// <param name="itemRenderer"></param>
	/// <param name="htmlAttributes"></param>
	/// <param name="filterEnums"></param>
	/// <param name="labelPositon"></param>
	/// <param name="separator"></param>
	/// <param name="beginTag"></param>
	/// <param name="itemTag"></param>
	/// <param name="renderRadioButtons"></param>
	/// <param name="labelsAsText"></param>
	/// <param name="labelAttributes"></param>
	/// <param name="itemsPerRow"></param>
	/// <param name="rowTag"></param>
	/// <param name="beginTagAttributes"></param>
	/// <param name="itemAttributes"></param>
	/// <param name="printLegend"></param>
	/// <param name="itemAction"></param>
	/// <param name="skipValues"></param>
	/// <returns></returns>
	/// <created author="laurentiu.macovei" date="Sat, 11 Feb 2012 02:56:31 GMT"/>
	private static HelperResult RenderEnum<TModel, TProperty>(HtmlHelper<TModel> htmlHelper,
		Expression<Func<TModel, TProperty>> expression, Func<HtmlHelper, ModelMetadata, string, string> buildHtmlFieldName,
		Action<HtmlHelper, int, string, string, TProperty, TProperty, IDictionary<string, object>, TextWriter> itemRenderer,
		object htmlAttributes, Func<TProperty, bool> filterEnums, LabelPostion labelPositon, string separator,
		string beginTag, string itemTag, bool renderRadioButtons, bool labelsAsText, object labelAttributes,
		int? itemsPerRow, string rowTag, object beginTagAttributes, object itemAttributes, bool printLegend,
		Action<int, TProperty, TextWriter> itemAction, int skipValues)
		where TProperty : IConvertible
	{
		return new HelperResult(sb =>
		{
			//var sb = new StringBuilder();
			var labelsBefore = labelPositon == LabelPostion.Before;
			var labelsAfter = labelPositon == LabelPostion.After;

			var htmlFieldId = expression == null ? htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId("") : ExpressionHelper.GetExpressionText(expression);
			var htmlFieldName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(htmlFieldId);
			ModelMetadata metadata = expression == null ? ModelMetadata.FromStringExpression(string.Empty, htmlHelper.ViewContext.ViewData) : ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
			TProperty value = (TProperty)(metadata.Model ?? (metadata.ModelType.IsValueType ? (dynamic)0 : null));
			htmlFieldId = TagBuilder.CreateSanitizedId(expression == null ? htmlFieldId : htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(htmlFieldId));
			//var htmlFieldName = htmlFieldId + "[]";
			htmlFieldName = buildHtmlFieldName != null ? buildHtmlFieldName(htmlHelper, metadata, htmlFieldName) : htmlFieldName;

			var dicAttributes = htmlAttributes as RouteValueDictionary;
			dicAttributes = dicAttributes ?? HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
			var dicBeginTagAttributes = beginTagAttributes as RouteValueDictionary;
			dicBeginTagAttributes = dicBeginTagAttributes ?? (beginTagAttributes == null ? null : HtmlHelper.AnonymousObjectToHtmlAttributes(beginTagAttributes));

			if (itemsPerRow.HasValue)
			{
				if (beginTag == "div")
					beginTag = "table";
				if (itemTag == null)
					itemTag = "td";
			}

			if (!dicAttributes.ContainsKey("class"))
				dicAttributes.Add("class", "radio");

			TagBuilder beginTagBuilder = null, rowBuilder = null;
			if (!string.IsNullOrWhiteSpace(beginTag))
			{
				beginTagBuilder = new TagBuilder(beginTag);
				if (dicBeginTagAttributes != null)
					beginTagBuilder.MergeAttributes(dicBeginTagAttributes);
				beginTagBuilder.MergeAttribute("class", "formee-list " + htmlFieldId, false);
				sb.Append(beginTagBuilder.ToString(TagRenderMode.StartTag));
			}
			if (itemsPerRow.HasValue && !string.IsNullOrEmpty(rowTag))
				rowBuilder = new TagBuilder(rowTag);

			if (printLegend)
			{
				var legendBuilder = new TagBuilder("legend");
				legendBuilder.InnerHtml = metadata.DisplayName ?? metadata.PropertyName;
				sb.Append(legendBuilder.ToString(TagRenderMode.Normal));
			}
			var insertSeparator = false;
			int index = 0;
			var itemType = value.GetType();
			var AsHtmlString = GetAsHtmlStringMethod(itemType);
			foreach (TProperty item in Enum.GetValues(itemType).Cast<TProperty>().Skip(skipValues))
				if (filterEnums == null || filterEnums(item))
				{
					if (itemAction != null)
						itemAction(index, item, sb);
					TagBuilder itemBuilder = null;
					if (rowBuilder != null)
					{
						if (index != 0 && index % itemsPerRow.Value == 0)
							sb.Append(rowBuilder.ToString(TagRenderMode.EndTag));
						if (index % itemsPerRow.Value == 0)
						{
							rowBuilder.Attributes["class"] = "row" + index / itemsPerRow.Value;
							sb.Append(rowBuilder.ToString(TagRenderMode.StartTag));
						}
						index++;
					}
					var fieldName = htmlFieldId + "_" + item.ToString();
					dicAttributes["id"] = fieldName;

					if (!string.IsNullOrWhiteSpace(itemTag))
					{
						itemBuilder = new TagBuilder(itemTag);
						var attrs = itemAttributes == null ? null : itemAttributes as IDictionary<string, object> ?? HtmlHelper.AnonymousObjectToHtmlAttributes(itemAttributes);
						var @class = fieldName;
						if (attrs != null)
						{
							@class = attrs["class"] as string;
							@class = string.IsNullOrWhiteSpace(@class) ? fieldName : fieldName + " " + @class;
						}
						itemBuilder.MergeAttributes(attrs);
						itemBuilder.Attributes["class"] = @class;
						sb.Append(itemBuilder.ToString(TagRenderMode.StartTag));
					}
					else if (insertSeparator)
					{
						sb.Append(separator);
					}
					else insertSeparator = true;
					string labelText = null;
					bool isHtmlLabel = false;
					if (labelPositon != LabelPostion.None)
					{
						var labelHtml = AsHtmlString(null, item);
						if (labelHtml is IHtmlString)
						{
							labelText = ((IHtmlString)labelHtml).ToHtmlString();
							isHtmlLabel = true;
						}
						else labelText = (labelHtml ?? string.Empty).ToString();
					}
					//var @for = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(null);
					//@for = htmlHelper.ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix == htmlFieldId ? fieldName : @for;//fieldName.Substring(String.IsNullOrEmpty(@for) ? 0 : @for.Length + 1) : fieldName;
					
					var @for = fieldName;
					if (labelsBefore)
					{
						if (labelsAsText)
							sb.Append(isHtmlLabel ? labelText : HttpUtility.HtmlEncode(labelText));
						else sb.Append(htmlHelper.Label(@for, labelText, html: isHtmlLabel, htmlAttributes: labelAttributes).ToHtmlString());
					}

					if (renderRadioButtons)
						itemRenderer(htmlHelper, index, htmlFieldName, htmlFieldId, item, value, dicAttributes, sb);
					if (labelsAfter)
					{
						if (labelsAsText)
							sb.Append(isHtmlLabel ? labelText : HttpUtility.HtmlEncode(labelText));
						else sb.Append(htmlHelper.Label(@for, labelText, html: isHtmlLabel, htmlAttributes: labelAttributes).ToHtmlString());
					}
					if (itemBuilder != null)
						sb.Append(itemBuilder.ToString(TagRenderMode.EndTag));
				}
			if (index != 0 && rowTag != null)
				sb.Append(rowBuilder.ToString(TagRenderMode.EndTag));
			//if (itemsPerRow.HasValue && index % itemsPerRow.Value != 0 && !string.IsNullOrEmpty(rowTag))
			//    sb.Append("</").Append(rowTag).Append(">");
			if (beginTagBuilder != null)
				sb.Append(beginTagBuilder.ToString(TagRenderMode.EndTag));
			//return new MvcHtmlString(sb.ToString());
		});
	}
	private static Dictionary<int, LateBoundMethod> _AsHtmlStringFastDelegates = new Dictionary<int, LateBoundMethod>();
	private static MethodInfo AsHtmlString_NonGeneric = typeof(EnumExtensions).GetMethod("AsHtmlString", BindingFlags.Static | BindingFlags.Public);
	/// <summary>
	/// </summary>
	/// <param name="itemType"></param>
	/// <returns></returns>
	/// <created author="laurentiu.macovei" date="Sat, 11 Feb 2012 02:56:31 GMT"/>
	private static LateBoundMethod GetAsHtmlStringMethod(Type itemType)
	{
		LateBoundMethod AsHtmlString;
		if (!_AsHtmlStringFastDelegates.TryGetValue(itemType.GetHashCode(), out AsHtmlString))
			lock (_AsHtmlStringFastDelegates)
				if (!_AsHtmlStringFastDelegates.TryGetValue(itemType.GetHashCode(), out AsHtmlString))
				{
					var generic = AsHtmlString_NonGeneric.MakeGenericMethod(itemType);
					_AsHtmlStringFastDelegates[itemType.GetHashCode()] = AsHtmlString = DelegateFactory.Create(generic);
				}
		return AsHtmlString;
	}

	private const string CheckBox_Value_NotSet = "value=\"\"";
	private const string CheckBox_Value_ValueFalse = "value=\"false\"";

	/// <summary>Renders a DropDownList for all (filtered) values of a given Enum</summary>
	/// <param name="htmlHelper">The HTML helper instance that this method extends.</param>
	/// <param name="expression"></param>
	/// <param name="filterEnums">A func to filter which enum values to be rendered. Return false to exclude those you don't want</param>
	/// <param name="optionLabel">The default text i.e. (Select an option)</param>
	/// <param name="skipCount">Specify how many values from the enum to skip. By default 1 to skip the NotSet. Specify 0 to render all</param>
	/// <param name="htmlAttributes">An object that contains the HTML attributes to set for each radio button element.</param>
	/// <created author="laurentiu.macovei" date="Tue, 22 Mar 2011 17:46:52 GMT"/>
	public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression,
		object htmlAttributes = null, Func<TProperty, bool> filterEnums = null,
		string optionLabel = null, int skipCount = 0)
		where TProperty : struct, IComparable, IFormattable, IConvertible
	{
		var sb = new StringBuilder();

		TProperty enumInstance = new TProperty();
		var enums = (IEnumerable<EnumExtensions.EnumInfo<TProperty>>)enumInstance.GetEnumerator();
		ModelMetadata modelMetaData = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
		TProperty value = (TProperty)(modelMetaData.Model ?? (modelMetaData.ModelType.IsValueType ? (object)default(TProperty) : null));
		dynamic intValue = value;


		object htmlAttributesObject;
		string placeholder = null;
		HtmlPropertiesAttribute htmlPropertiesAttribute = null;
		var additionalValues = modelMetaData.AdditionalValues;
		if (additionalValues.Any())
		{
			if (additionalValues.TryGetValue("HtmlAttributes", out htmlAttributesObject))
			{
				htmlPropertiesAttribute = htmlAttributesObject as HtmlPropertiesAttribute;
			}
			if (additionalValues.TryGetValue("placeholder", out htmlAttributesObject))
			{
				placeholder = htmlAttributesObject as string;
			}
		}
		var htmlDicAttributes = HtmlPropertiesAttribute.Merge(htmlHelper.ViewContext.Controller.CanOutputKnockout()
			  ? new RouteValueDictionary { { "data-bind", "value: " + modelMetaData.PropertyName } } : null,
			  htmlHelper.ViewContext.RequestContext.HttpContext.Request.IsMobile()
			  ? new RouteValueDictionary { { "data-theme", "c" }, { "data-native-menu", "false" } } : null,
			  htmlPropertiesAttribute, placeholder == null ? null : new { placeholder },
			  htmlAttributes);

		if (filterEnums != null)
			enums = enums.Where(e => filterEnums(e.Enum));
		var ddl = htmlHelper.SelectInternal(optionLabel, ExpressionHelper.GetExpressionText(expression),
			enums.Skip(skipCount).Select(e =>//skip the NotSet value
			{
				var labelText = (e.Description ?? string.Empty).ToString();
				var val = e.Value;
				return new SelectListItem { Text = labelText, Value = val.ToString(), Selected = intValue.Equals(val) };
			}), false, htmlDicAttributes);

		return ddl;
	}
	/// <summary>
	/// </summary>
	/// <param name="htmlHelper"></param>
	/// <param name="optionLabel">The default text i.e. (Select an option)</param>
	/// <param name="name"></param>
	/// <param name="selectList"></param>
	/// <param name="allowMultiple"></param>
	/// <param name="htmlAttributes"></param>
	/// <returns></returns>
	/// <created author="laurentiu.macovei" date="Sat, 26 Mar 2011 14:36:02 GMT"/>
	private static MvcHtmlString SelectInternal(this HtmlHelper htmlHelper, string optionLabel, string name, IEnumerable<SelectListItem> selectList, bool allowMultiple, IDictionary<string, object> htmlAttributes)
	{
		string fullName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);
		if (String.IsNullOrEmpty(fullName))
		{
			throw new ArgumentException("Common_NullOrEmpty", "name");
		}

		bool usedViewData = false;

		// If we got a null selectList, try to use ViewData to get the list of items.
		if (selectList == null)
		{
			selectList = htmlHelper.GetSelectData(fullName);
			usedViewData = true;
		}

		object defaultValue = (allowMultiple) ? htmlHelper.GetModelStateValue(fullName, typeof(string[])) : htmlHelper.GetModelStateValue(fullName, typeof(string));

		// If we haven't already used ViewData to get the entire list of items then we need to
		// use the ViewData-supplied value before using the parameter-supplied value.
		if (!usedViewData)
		{
			if (defaultValue == null)
			{
				defaultValue = htmlHelper.ViewData.Eval(fullName);
			}
			if (defaultValue is Enum)
			{
				//hack the enum so we store the int/byte/long value rather than the enum itself 
				//which would cause to serialize as "Name" of the enum rather than its value
				defaultValue = ((IConvertible)defaultValue).ToInt64(CultureInfo.CurrentCulture);
			}
		}

		if (defaultValue != null)
		{
			IEnumerable defaultValues = (allowMultiple) ? defaultValue as IEnumerable : new[] { defaultValue };
			IEnumerable<string> values = from object value in defaultValues select Convert.ToString(value, CultureInfo.CurrentCulture);
			HashSet<string> selectedValues = new HashSet<string>(values, StringComparer.OrdinalIgnoreCase);
			List<SelectListItem> newSelectList = new List<SelectListItem>();

			foreach (SelectListItem item in selectList)
			{
				item.Selected = (item.Value != null) ? selectedValues.Contains(item.Value) : selectedValues.Contains(item.Text);
				newSelectList.Add(item);
			}
			selectList = newSelectList;
		}

		// Convert each ListItem to an <option> tag
		StringBuilder listItemBuilder = new StringBuilder();

		// Make optionLabel the first item that gets rendered.
		if (optionLabel != null)
		{
			listItemBuilder.AppendLine(ListItemToOption(new SelectListItem() { Text = optionLabel, Value = String.Empty, Selected = false }));
		}

		foreach (SelectListItem item in selectList)
		{
			listItemBuilder.AppendLine(ListItemToOption(item));
		}

		TagBuilder tagBuilder = new TagBuilder("select")
		{
			InnerHtml = listItemBuilder.ToString()
		};
		tagBuilder.MergeAttributes(htmlAttributes);
		tagBuilder.MergeAttribute("name", fullName, true /* replaceExisting */);
		tagBuilder.GenerateId(fullName);
		if (allowMultiple)
		{
			tagBuilder.MergeAttribute("multiple", "multiple");
		}

		// If there are any errors for a named field, we add the css attribute.
		ModelState modelState;
		if (htmlHelper.ViewData.ModelState.TryGetValue(fullName, out modelState))
		{
			if (modelState.Errors.Count > 0)
			{
				tagBuilder.AddCssClass(HtmlHelper.ValidationInputCssClassName);
			}
		}

		tagBuilder.MergeAttributes(htmlHelper.GetUnobtrusiveValidationAttributes(name));

		return tagBuilder.ToMvcHtmlString(TagRenderMode.Normal);
	}
	/// <summary>
	/// </summary>
	/// <param name="htmlHelper"></param>
	/// <param name="name"></param>
	/// <returns></returns>
	/// <created author="laurentiu.macovei" date="Sat, 26 Mar 2011 14:36:02 GMT"/>
	private static IEnumerable<SelectListItem> GetSelectData(this HtmlHelper htmlHelper, string name)
	{
		object o = null;
		if (htmlHelper.ViewData != null)
		{
			o = htmlHelper.ViewData.Eval(name);
		}
		if (o == null)
		{
			throw new InvalidOperationException(
				String.Format(
					CultureInfo.CurrentCulture,
					"HtmlHelper_MissingSelectData",
					name,
					"IEnumerable<SelectListItem>"));
		}
		IEnumerable<SelectListItem> selectList = o as IEnumerable<SelectListItem>;
		if (selectList == null)
		{
			throw new InvalidOperationException(
				String.Format(
					CultureInfo.CurrentCulture,
					"HtmlHelper_WrongSelectDataType",
					name,
					o.GetType().FullName,
					"IEnumerable<SelectListItem>"));
		}
		return selectList;
	}
	/// <summary>
	/// </summary>
	/// <param name="tagBuilder"></param>
	/// <param name="renderMode"></param>
	/// <returns></returns>
	/// <created author="laurentiu.macovei" date="Sat, 26 Mar 2011 14:36:03 GMT"/>
	internal static MvcHtmlString ToMvcHtmlString(this TagBuilder tagBuilder, TagRenderMode renderMode)
	{
		return new MvcHtmlString(tagBuilder.ToString(renderMode));
	}
	/// <summary>
	/// </summary>
	/// <param name="htmlHelper"></param>
	/// <param name="key"></param>
	/// <param name="destinationType"></param>
	/// <returns></returns>
	/// <created author="laurentiu.macovei" date="Sat, 26 Mar 2011 14:36:03 GMT"/>
	internal static object GetModelStateValue(this HtmlHelper htmlHelper, string key, Type destinationType)
	{
		ModelState modelState;
		if (htmlHelper.ViewData.ModelState.TryGetValue(key, out modelState))
		{
			if (modelState.Value != null)
			{
				return modelState.Value.ConvertTo(destinationType, null /* culture */);
			}
		}
		return null;
	}
	/// <summary>
	/// </summary>
	/// <param name="item"></param>
	/// <returns></returns>
	/// <created author="laurentiu.macovei" date="Sat, 26 Mar 2011 14:36:03 GMT"/>
	internal static string ListItemToOption(SelectListItem item)
	{
		TagBuilder builder = new TagBuilder("option")
		{
			InnerHtml = HttpUtility.HtmlEncode(item.Text)
		};
		if (item.Value != null)
		{
			builder.Attributes["value"] = item.Value;
		}
		if (item.Selected)
		{
			builder.Attributes["selected"] = "selected";
		}
		return builder.ToString(TagRenderMode.Normal);
	}


	/// <summary>
	/// Returns an HTML label element and the property name of the property that
	/// is represented by the specified expression.
	/// </summary>
	/// <typeparam name="TModel">The type of the model.</typeparam>
	/// <param name="htmlHelper">The HTML helper instance that this method extends.</param>
	/// <param name="expression">An expression that identifies the property to display.</param>
	/// <param name="labelText">Optional custom label text.</param>
	/// <param name="htmlAttributes">An object that contains the HTML attributes to set for the element.</param>
	/// <param name="html">Specify true if the label text contains html</param>
	/// <param name="requiredLabelHtml">Specify a custom html if the property is required to draw a hint i.e. an *. <para>Defaults to &lt;em class="formee-req"&gt;*&lt;/em&gt;</para></param>
	/// <param name="tagName">Specify the tag name to be printed out i.e. label</param>
	/// <returns>An HTML label element and the property name of the property that is represented by the expression.</returns>
	/// <created author="laurentiu.macovei" date="Sun, 20 Mar 2011 18:20:34 GMT"/>
	public static MvcHtmlString Label<TModel>(this HtmlHelper<TModel> htmlHelper, string expression, string labelText = null, object htmlAttributes = null, bool html = false, string requiredLabelHtml = null, string tagName = "label")
	{
		return LabelHelper(htmlHelper,
						   ModelMetadata.FromStringExpression(expression, htmlHelper.ViewData),
						   expression,
						   labelText, htmlAttributes, html, requiredLabelHtml, tagName);
	}
	/// <returns>An HTML label element and the property name of the property that is represented by the expression.</returns>
	/// <param name="htmlHelper">The HTML helper instance that this method extends.</param>
	/// <param name="expression">An expression that identifies the property to display.</param>
	/// <typeparam name="TModel">The type of the model.</typeparam>
	/// <typeparam name="TProperty">The type of the value.</typeparam>
	/// <param name="labelText">Optional custom label text.</param>
	/// <param name="htmlAttributes">An object that contains the HTML attributes to set for the element.</param>
	/// <param name="html">Specify true whether the text of the label contains html</param>
	/// <param name="tagName">Specify the tag name to be printed out i.e. label</param>
	/// <param name="requiredLabelHtml">Specify a custom html if the property is required to draw a hint i.e. an *. <para>Defaults to &lt;em class="formee-req"&gt;*&lt;/em&gt;</para></param>
	/// <created author="laurentiu.macovei" date="Sun, 20 Mar 2011 06:20:01 GMT"/>
	public static MvcHtmlString LabelFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, string labelText = null, object htmlAttributes = null, bool html = false, string requiredLabelHtml = null, string tagName = "label")
	{
		return LabelHelper(htmlHelper,
						   ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData),
						   ExpressionHelper.GetExpressionText(expression),
						   labelText, htmlAttributes, html, requiredLabelHtml, tagName);
	}
	/// <returns>An HTML label element and the property name of the property that is represented by the expression.</returns>
	/// <param name="htmlHelper">The HTML helper instance that this method extends.</param>
	/// <param name="expression">An expression that identifies the property to display.</param>
	/// <typeparam name="TModel">The type of the model.</typeparam>
	/// <typeparam name="TProperty">The type of the value.</typeparam>
	/// <param name="labelText">Optional custom label text.</param>
	/// <param name="htmlAttributes">An object that contains the HTML attributes to set for the element.</param>
	/// <param name="html">Specify true whether the text of the label contains html</param>
	/// <param name="requiredLabelHtml">Specify a custom html if the property is required to draw a hint i.e. an *. <para>Defaults to &lt;em class="formee-req"&gt;*&lt;/em&gt;</para></param>
	/// <param name="tagName">Specify the tag name to be printed out i.e. label</param>
	/// <created author="laurentiu.macovei" date="Sun, 20 Mar 2011 06:20:01 GMT"/>
	public static MvcHtmlString LabelForr<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, string labelText = null, object htmlAttributes = null, bool html = false, string requiredLabelHtml = null, string tagName = "label")
	{
		return LabelHelper(htmlHelper,
						   ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData),
						   ExpressionHelper.GetExpressionText(expression),
						   labelText, htmlAttributes, html, requiredLabelHtml, tagName);
	}

	/// <returns>An HTML label element and the property name of the property that is represented by the expression.</returns>
	/// <param name="htmlHelper">The HTML helper instance that this method extends.</param>
	/// <param name="metadata"></param>
	/// <param name="htmlFieldName">The name of the field</param>
	/// <param name="labelText">Optional custom label text.</param>
	/// <param name="htmlAttributes">An object that contains the HTML attributes to set for the element.</param>
	/// <param name="requiredLabelText">Specify a custom text if the property is required to draw a hint i.e. an *. <para>Defaults to &lt;em class="formee-req"&gt;*&lt;/em&gt;</para></param>
	/// <param name="tagName">Specify the tag name to be printed out i.e. label</param>
	/// <param name="html">Specify true whether the text of the label contains html</param>
	/// <created author="laurentiu.macovei" date="Sun, 20 Mar 2011 06:20:01 GMT"/>
	internal static MvcHtmlString LabelHelper(HtmlHelper htmlHelper, ModelMetadata metadata, string htmlFieldName, string labelText = null, object htmlAttributes = null, bool html = false, string requiredLabelText = null, string tagName = "label")
	{
		string resolvedLabelText = labelText ?? metadata.DisplayName ?? metadata.PropertyName ?? htmlFieldName.Split('.').Last();
		if (String.IsNullOrEmpty(resolvedLabelText))
		{
			return MvcHtmlString.Empty;
		}

		TagBuilder tag = new TagBuilder(tagName);
		tag.Attributes.Add("for", TagBuilder.CreateSanitizedId(htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(htmlFieldName)));
		var attrs = htmlAttributes as RouteValueDictionary;
		attrs = attrs ?? HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);

		tag.MergeAttributes(attrs);
		if (html)
			tag.InnerHtml = resolvedLabelText;
		else tag.SetInnerText(resolvedLabelText);
		if (metadata.IsRequired)
			tag.InnerHtml += requiredLabelText ?? MvcConfig.RequiredLabelText;
		return new MvcHtmlString(tag.ToString(TagRenderMode.Normal));
	}
	/// <summary>Serializes the given model state in a json compatible dictionary</summary>
	/// <param name="modelState">The model state to be serialized</param>
	/// <created author="laurentiu.macovei" date="Fri, 18 Mar 2011 02:23:32 GMT"/>
	[DebuggerStepThrough]
	public static Dictionary<string, ModelErrorCollection> ToJson(this ModelStateDictionary modelState)
	{
		return modelState == null ? null : modelState.ToDictionary(e => e.Key, e => e.Value.Errors);
	}

	/// <summary>Returns true if the current user is logged in</summary>
	/// <param name="user"></param>
	/// <created author="laurentiu.macovei" date="Sat, 12 Mar 2011 18:28:32 GMT"/>
	public static bool IsLogged(this IPrincipal user)
	{
		return user.Identity.IsAuthenticated;
	}

	/// <summary>Returns true if the current user is NOT logged in</summary>
	/// <param name="user"></param>
	/// <created author="laurentiu.macovei" date="Sat, 12 Mar 2011 18:28:32 GMT"/>
	public static bool NotLogged(this IPrincipal user)
	{
		return !user.Identity.IsAuthenticated;
	}

	/// <summary>Serializes the object as json</summary>
	/// <param name="controller">The controller being extended</param>
	/// <param name="o"></param>
	/// <returns></returns>
	/// <created author="laurentiu.macovei" date="Sat, 29 Jan 2011 19:01:03 GMT"/>
	public static string ToJson(this Controller controller, object o)
	{
		var serializer = new JavaScriptSerializer();
		var json = serializer.Serialize(o);
		return json;
	}

	/// <summary>Renders the section with some new default content</summary>
	/// <param name="page"></param>
	/// <param name="sectionName"></param>
	/// <param name="defaultContent"></param>
	/// <returns></returns>
	/// <created author="laurentiu.macovei" date="Sun, 09 Jan 2011 21:37:57 GMT"/>
	public static HelperResult RenderSection(this WebPageBase page,
						string sectionName,
						Func<object, HelperResult> defaultContent)
	{
		if (page.IsSectionDefined(sectionName))
		{
			return page.RenderSection(sectionName);
		}
		else
		{
			return defaultContent(_o);
		}
	}

	/// <summary>
	/// </summary>
	/// <param name="page"></param>
	/// <param name="sectionName"></param>
	/// <param name="defaultContent"></param>
	/// <param name="dependinces"></param>
	/// <returns></returns>
	/// <created author="laurentiu.macovei" date="Fri, 18 Mar 2011 02:23:32 GMT"/>
	public static DependentSection DefaultSection(this WebPageBase page, string sectionName,
						Func<object, HelperResult> defaultContent, params DependentSection[] dependinces)
	{
		if (page.IsSectionDefined(sectionName))
		{
			return null;
		}
		else
		{
			return new DependentSection { Name = sectionName, DefaultContent = defaultContent, Dependinces = dependinces };
		}
	}

	/// <summary>
	/// </summary>
	/// <param name="page"></param>
	/// <param name="sectionName"></param>
	/// <param name="defaultContent"></param>
	/// <param name="dependinces"></param>
	/// <returns></returns>
	/// <created author="laurentiu.macovei" date="Fri, 18 Mar 2011 02:23:32 GMT"/>
	public static HelperResult RenderSection(this WebPageBase page,
						string sectionName,
						Func<object, HelperResult> defaultContent,
						params DependentSection[] dependinces
		)
	{
		if (page.IsSectionDefined(sectionName))
		{
			return page.RenderSection(sectionName);
		}
		else
		{
			if (dependinces != null && dependinces.Length > 0)
			{
				var stack = page.GetSectionWritersStack().ToArray();
				foreach (var section in dependinces)
				{
					section.DefineDefaults(page, stack);
				}
			}
			return defaultContent(_o);
		}
	}

	/// <summary>
	/// </summary>
	/// <param name="page"></param>
	/// <param name="sectionName"></param>
	/// <param name="defaultContent"></param>
	/// <returns></returns>
	/// <created author="laurentiu.macovei" date="Fri, 11 Mar 2011 21:47:47 GMT"/>
	public static HelperResult RenderSection(this WebPageBase page,
						string sectionName,
						string defaultContent)
	{
		if (page.IsSectionDefined(sectionName))
		{
			return page.RenderSection(sectionName);
		}
		else
		{
			return new HelperResult(a => a.Write(defaultContent));
		}
	}

	/// <summary>
	/// </summary>
	/// <param name="page"></param>
	/// <param name="sectionName"></param>
	/// <param name="defaultContent"></param>
	/// <returns></returns>
	/// <created author="laurentiu.macovei" date="Fri, 11 Mar 2011 21:59:50 GMT"/>
	public static HelperResult RenderSection(this WebPageBase page,
						string sectionName,
						MvcHtmlString defaultContent)
	{
		if (page.IsSectionDefined(sectionName))
		{
			return page.RenderSection(sectionName);
		}
		else
		{
			return new HelperResult(a => a.Write(defaultContent));
		}
	}

	/// <summary>Returns the MvcHtmlString of the given section if defined or the fallback default value</summary>
	/// <param name="page"></param>
	/// <param name="sectionName"></param>
	/// <param name="defaultContent"></param>
	/// <param name="dependinces"></param>
	/// <created author="laurentiu.macovei" date="Sun, 20 Mar 2011 02:55:35 GMT"/>
	public static MvcHtmlString RenderSectionAsHtml(this WebPageBase page,
						string sectionName,
						Func<object, HelperResult> defaultContent,
						params DependentSection[] dependinces
		)
	{
		if (page.IsSectionDefined(sectionName))
		{
			return new MvcHtmlString(page.RenderSection(sectionName).ToHtmlString());
		}
		else
		{
			if (dependinces != null && dependinces.Length > 0)
			{
				var stack = page.GetSectionWritersStack().ToArray();
				foreach (var section in dependinces)
				{
					section.DefineDefaults(page, stack);
				}
			}
			return new MvcHtmlString(defaultContent(_o).ToHtmlString());
		}
	}

	/// <summary>
	/// </summary>
	/// <param name="page"></param>
	/// <param name="sectionName"></param>
	/// <param name="defaultContent"></param>
	/// <returns></returns>
	/// <created author="laurentiu.macovei" date="Sun, 20 Mar 2011 02:55:35 GMT"/>
	public static MvcHtmlString RenderSectionAsHtml(this WebPageBase page,
						string sectionName,
						string defaultContent)
	{
		if (page.IsSectionDefined(sectionName))
		{
			return new MvcHtmlString(page.RenderSection(sectionName).ToHtmlString());
		}
		else
		{
			return new MvcHtmlString(defaultContent);
		}
	}

	/// <summary>
	/// </summary>
	/// <param name="page"></param>
	/// <param name="sectionName"></param>
	/// <param name="defaultContent"></param>
	/// <returns></returns>
	/// <created author="laurentiu.macovei" date="Sun, 20 Mar 2011 02:55:35 GMT"/>
	public static MvcHtmlString RenderSectionAsHtml(this WebPageBase page,
						string sectionName,
						MvcHtmlString defaultContent)
	{
		if (page.IsSectionDefined(sectionName))
		{
			return new MvcHtmlString(page.RenderSection(sectionName).ToHtmlString());
		}
		else
		{
			return defaultContent;
		}
	}

	/// <summary>Redefines a section and keeps the old default content</summary>
	/// <param name="page"></param>
	/// <param name="sectionName"></param>
	/// <returns></returns>
	/// <created author="laurentiu.macovei" date="Sun, 09 Jan 2011 21:37:57 GMT"/>
	public static HelperResult RedefineSection(this WebPageBase page,
		string sectionName)
	{
		return RedefineSection(page, sectionName, defaultContent: null);
	}

	/// <summary>Redefines a section with some new "default content"</summary>
	/// <param name="page"></param>
	/// <param name="sectionName"></param>
	/// <param name="defaultContent"></param>
	/// <returns></returns>
	/// <created author="laurentiu.macovei" date="Sun, 09 Jan 2011 21:37:58 GMT"/>
	public static HelperResult RedefineSection(this WebPageBase page,
							string sectionName,
							Func<object, HelperResult> defaultContent)
	{
		if (page.IsSectionDefined(sectionName))
		{
			page.DefineSection(sectionName,
							   () => page.Write(page.RenderSection(sectionName)));
			//var hiddenResult = page.RenderSection(sectionName);
			//page.GetPreviousWriters[sectionName]
		}
		else if (defaultContent != null)
		{
			page.DefineSection(sectionName,
							   () => page.Write(defaultContent(_o)));
		}
		return Empty;
	}

	/// <summary>
	/// </summary>
	/// <param name="page"></param>
	/// <param name="sections"></param>
	/// <param name="onlyChildSections"></param>
	/// <returns></returns>
	/// <created author="laurentiu.macovei" date="Fri, 18 Mar 2011 02:23:32 GMT"/>
	public static HelperResult PurgeSections(this WebPageBase page, string sections, bool onlyChildSections = false)
	{
		if (!string.IsNullOrEmpty(sections))
		{
			var previousWriters = page.GetPreviousWriters();
			var currentWriters = page.GetSectionWritersStack().Peek();
			foreach (var section in sections.Split(',', StringSplitOptions.RemoveEmptyEntries))
			{
				previousWriters.Remove(sections);
				if (!onlyChildSections)
					currentWriters.Remove(sections);
			}
		}
		return Empty;
	}
	/// <summary>Returns the suffix for the day of the current date i.e. st, nd, rd, or th</summary>
	/// <param name="date">Specify the date to print the suffix for its day</param>
	/// <param name="printNumber">Specify true to return the day and then the suffix</param>
	/// <created author="laurentiu.macovei" date="Sat, 26 Mar 2011 14:36:04 GMT"/>
	public static string DaySuffix(this DateTime date, bool printNumber = true)
	{
		return date.Day.Suffix(printNumber);
	}

	/// <summary>Returns the suffix for the given number i.e. st, nd, rd, or th</summary>
	/// <param name="number">Specify the number to return its suffix for</param>
	/// <param name="printNumber">Specify true to return the day and then the suffix</param>
	/// <created author="laurentiu.macovei" date="Sat, 26 Mar 2011 14:39:53 GMT"/>
	public static string Suffix(this int number, bool printNumber = true)
	{
		string n = printNumber ? number.ToString() : null;
		switch (number)
		{
			case 1:
			case 21:
			case 31:
				return n + "st";
			case 2:
			case 22:
				return n + "nd";
			case 3:
			case 23:
				return n + "rd";
			default:
				return n + "th";
		}
	}
	/// <summary>Redefines all the previous defined sections</summary>
	/// <param name="page"></param>
	/// <param name="includeSections">Specify which sections to be redefined. If null provided, all of them will be redefined</param>
	/// <param name="exceptSections">Specify which sections not to be redefined</param>
	/// <returns></returns>
	/// <created author="laurentiu.macovei" date="Sat, 12 Mar 2011 01:25:40 GMT"/>
	public static HelperResult RedefineSections(this WebPageBase page, string includeSections = null, string exceptSections = null)
	{
		var previousWriters = page.GetPreviousWriters();
		var sections = includeSections == null ? (previousWriters == null ? null : previousWriters.Select(i => i.Key)) : includeSections.Split(',', StringSplitOptions.RemoveEmptyEntries);
		var except = exceptSections == null ? null : exceptSections.Split(',', StringSplitOptions.RemoveEmptyEntries);
		if (sections != null)
			foreach (var item in sections.Except(except ?? new string[0]))
				page.RedefineSection(item);
		return new HelperResult(_ => { });
	}

	/// <summary>Renders the content if the current logged in user is in any provided roles (separated by comma)</summary>
	/// <param name="page"></param>
	/// <param name="roles"></param>
	/// <param name="content"></param>
	/// <returns></returns>
	/// <created author="laurentiu.macovei" date="Thu, 13 Jan 2011 17:31:46 GMT"/>
	public static HelperResult Role(this WebPageBase page, string roles, Func<object, HelperResult> content)
	{
		if (!string.IsNullOrEmpty(roles))
		{
			var user = page.User;
			if (roles.IndexOf(',') > 0)
			{
				var ro = roles.Split(',', StringSplitOptions.RemoveEmptyEntries);
				foreach (var r in ro)
				{
					if (user.IsInRole(r))
					{
						page.Write(content(_o));
					}
				}
			}
			else
				if (user.IsInRole(roles))
					page.Write(content(_o));
		}
		return new HelperResult(_ => { });
	}

	/// <summary>Renders the content if there is a current logged in user</summary>
	/// <param name="page"></param>
	/// <param name="content"></param>
	/// <returns></returns>
	/// <created author="laurentiu.macovei" date="Thu, 13 Jan 2011 17:31:46 GMT"/>
	public static HelperResult Logged(this WebPageBase page, Func<object, HelperResult> content)
	{
		if (page.User.Identity.IsAuthenticated)
			return new HelperResult(_ => _.Write(content(_o).ToString()));
		return new HelperResult(_ => { });
	}

	/// <summary>Determines whether the current principal belongs to any of the specified roles.</summary>
	/// <param name="user">The user to check the roles for</param>
	/// <param name="roles">The role names for which to check membership.</param>
	/// <returns>true if the current principal is a member of the specified role; otherwise, false.</returns>
	/// <created author="laurentiu.macovei" date="Sat, 29 Jan 2011 16:51:19 GMT"/>
	public static bool IsInRole(this IPrincipal user, params string[] roles)
	{
		if (user == null)
			return roles == null || roles.Length == 0;
		return roles.Any(r => user.IsInRole(r));
	}

	/// <summary>Returns an HTML textarea element for each property in the object that is represented by the specified expression.</summary>
	/// <returns>An HTML textarea element for each property in the object that is represented by the expression.</returns>
	/// <param name="htmlHelper">The HTML helper instance that this method extends.</param>
	/// <param name="expression">An expression that identifies the object that contains the properties to render.</param>
	/// <typeparam name="TModel">The type of the model.</typeparam>
	/// <typeparam name="TProperty">The type of the property.</typeparam>
	/// <exception cref="T:System.ArgumentNullException">The <paramref name="expression"/> parameter is null.</exception>
	/// <created author="laurentiu.macovei" date="Tue, 12 Apr 2011 00:41:28 GMT"/>
	public static MvcHtmlString TextAreaForHtml<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
	{
		return htmlHelper.TextAreaForHtml<TModel, TProperty>(expression, ((IDictionary<string, object>)null));
	}

	/// <summary>Returns an HTML textarea element for each property in the object that is represented by the specified expression using the specified HTML attributes.</summary>
	/// <returns>An HTML textarea element for each property in the object that is represented by the expression.</returns>
	/// <param name="htmlHelper">The HTML helper instance that this method extends.</param>
	/// <param name="expression">An expression that identifies the object that contains the properties to render.</param>
	/// <param name="htmlAttributes">A dictionary that contains the HTML attributes to set for the element.</param>
	/// <typeparam name="TModel">The type of the model.</typeparam>
	/// <typeparam name="TProperty">The type of the property.</typeparam>
	/// <exception cref="T:System.ArgumentNullException">The <paramref name="expression"/> parameter is null.</exception>
	/// <created author="laurentiu.macovei" date="Tue, 12 Apr 2011 00:41:28 GMT"/>
	public static MvcHtmlString TextAreaForHtml<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IDictionary<string, object> htmlAttributes)
	{
		if (expression == null)
		{
			throw new ArgumentNullException("expression");
		}
		return TextAreaHelperHtml(htmlHelper, ModelMetadata.FromLambdaExpression<TModel, TProperty>(expression, htmlHelper.ViewData), ExpressionHelper.GetExpressionText(expression), implicitRowsAndColumns, htmlAttributes);
	}

	/// <summary>Returns an HTML textarea element for each property in the object that is represented by the specified expression using the specified HTML attributes.</summary>
	/// <returns>An HTML textarea element for each property in the object that is represented by the expression.</returns>
	/// <param name="htmlHelper">The HTML helper instance that this method extends.</param>
	/// <param name="expression">An expression that identifies the object that contains the properties to render.</param>
	/// <param name="htmlAttributes">A dictionary that contains the HTML attributes to set for the element.</param>
	/// <typeparam name="TModel">The type of the model.</typeparam>
	/// <typeparam name="TProperty">The type of the property.</typeparam>
	/// <exception cref="T:System.ArgumentNullException">The <paramref name="expression"/> parameter is null.</exception>
	/// <created author="laurentiu.macovei" date="Tue, 12 Apr 2011 00:46:08 GMT"/>
	public static MvcHtmlString TextAreaForHtml<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes)
	{
		return htmlHelper.TextAreaForHtml<TModel, TProperty>(expression, ((IDictionary<string, object>)HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes)));
	}

	/// <summary>Returns an HTML textarea element for each property in the object that is represented by the specified expression using the specified HTML attributes and the number of rows and columns.</summary>
	/// <returns>An HTML textarea element for each property in the object that is represented by the expression.</returns>
	/// <param name="htmlHelper">The HTML helper instance that this method extends.</param>
	/// <param name="expression">An expression that identifies the object that contains the properties to render.</param>
	/// <param name="rows">The number of rows.</param>
	/// <param name="columns">The number of columns.</param>
	/// <param name="htmlAttributes">A dictionary that contains the HTML attributes to set for the element.</param>
	/// <typeparam name="TModel">The type of the model.</typeparam>
	/// <typeparam name="TProperty">The type of the property.</typeparam>
	/// <exception cref="T:System.ArgumentNullException">The <paramref name="expression"/> parameter is null.</exception>
	/// <created author="laurentiu.macovei" date="Tue, 12 Apr 2011 00:41:28 GMT"/>
	public static MvcHtmlString TextAreaForHtml<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, int rows, int columns, IDictionary<string, object> htmlAttributes)
	{
		if (expression == null)
		{
			throw new ArgumentNullException("expression");
		}
		return TextAreaHelperHtml(htmlHelper, ModelMetadata.FromLambdaExpression<TModel, TProperty>(expression, htmlHelper.ViewData), ExpressionHelper.GetExpressionText(expression), GetRowsAndColumnsDictionary(rows, columns), htmlAttributes);
	}
	/// <summary>Returns a new dictionary containing the rows and columns</summary>
	/// <param name="rows">The rows to be contained</param>
	/// <param name="columns">The columns to be contained</param>
	/// <created author="laurentiu.macovei" date="Tue, 12 Apr 2011 00:41:28 GMT"/>
	private static Dictionary<string, object> GetRowsAndColumnsDictionary(int rows, int columns)
	{
		if (rows < 0)
		{
			throw new ArgumentOutOfRangeException("rows", "The value must be greater than or equal to zero.");
		}
		if (columns < 0)
		{
			throw new ArgumentOutOfRangeException("columns", "The value must be greater than or equal to zero.");
		}
		Dictionary<string, object> dictionary = new Dictionary<string, object>();
		if (rows > 0)
		{
			dictionary.Add("rows", rows.ToString(CultureInfo.InvariantCulture));
		}
		if (columns > 0)
		{
			dictionary.Add("cols", columns.ToString(CultureInfo.InvariantCulture));
		}
		return dictionary;
	}

	/// <summary>Returns an HTML textarea element for each property in the object that is represented by the specified expression using the specified HTML attributes and the number of rows and columns.</summary>
	/// <returns>An HTML textarea element for each property in the object that is represented by the expression.</returns>
	/// <param name="htmlHelper">The HTML helper instance that this method extends.</param>
	/// <param name="expression">An expression that identifies the object that contains the properties to render.</param>
	/// <param name="rows">The number of rows.</param>
	/// <param name="columns">The number of columns.</param>
	/// <param name="htmlAttributes">A dictionary that contains the HTML attributes to set for the element.</param>
	/// <typeparam name="TModel">The type of the model.</typeparam>
	/// <typeparam name="TProperty">The type of the property.</typeparam>
	/// <exception cref="T:System.ArgumentNullException">The <paramref name="expression"/> parameter is null.</exception>
	/// <created author="laurentiu.macovei" date="Tue, 12 Apr 2011 00:41:28 GMT"/>
	public static MvcHtmlString TextAreaForHtml<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, int rows, int columns, object htmlAttributes)
	{
		return htmlHelper.TextAreaForHtml<TModel, TProperty>(expression, rows, columns, ((IDictionary<string, object>)HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes)));
	}

	/// <summary>
	/// Creates a new text area but not encodes the html
	/// </summary>
	/// <param name="htmlHelper">The HTML helper instance that this method extends.</param>
	/// <param name="modelMetadata"></param>
	/// <param name="name"></param>
	/// <param name="rowsAndColumns">The dictionary with rows and columns</param>
	/// <param name="htmlAttributes">A dictionary that contains the HTML attributes to set for the element.</param>
	/// <returns></returns>
	/// <created author="laurentiu.macovei" date="Tue, 12 Apr 2011 00:41:28 GMT"/>
	private static MvcHtmlString TextAreaHelperHtml(HtmlHelper htmlHelper, ModelMetadata modelMetadata, string name, IDictionary<string, object> rowsAndColumns, IDictionary<string, object> htmlAttributes)
	{
		ModelState state;
		string attemptedValue;
		string fullHtmlFieldName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);
		if (string.IsNullOrEmpty(fullHtmlFieldName))
		{
			throw new ArgumentException("Value cannot be null or empty.", "name");
		}
		TagBuilder tagBuilder = new TagBuilder("textarea");
		tagBuilder.GenerateId(fullHtmlFieldName);
		tagBuilder.MergeAttributes<string, object>(htmlAttributes, true);
		tagBuilder.MergeAttributes<string, object>(rowsAndColumns, rowsAndColumns != implicitRowsAndColumns);
		tagBuilder.MergeAttribute("name", fullHtmlFieldName, true);
		if (htmlHelper.ViewData.ModelState.TryGetValue(fullHtmlFieldName, out state) && (state.Errors.Count > 0))
		{
			tagBuilder.AddCssClass(HtmlHelper.ValidationInputCssClassName);
		}
		tagBuilder.MergeAttributes<string, object>(htmlHelper.GetUnobtrusiveValidationAttributes(name));
		if ((state != null) && (state.Value != null))
		{
			attemptedValue = state.Value.AttemptedValue;
		}
		else if (modelMetadata.Model != null)
		{
			attemptedValue = modelMetadata.Model.ToString();
		}
		else
		{
			attemptedValue = string.Empty;
		}
		tagBuilder.InnerHtml = Environment.NewLine + attemptedValue;
		return tagBuilder.ToMvcHtmlString(TagRenderMode.Normal);
	}

	/// <summary>Static constructor of SectionExtensions</summary>
	/// <created author="laurentiu.macovei" date="Tue, 12 Apr 2011 00:41:24 GMT"/>
	static SectionExtensions()
	{
		Dictionary<string, object> dictionary = new Dictionary<string, object>();
		dictionary.Add("rows", 2.ToString(CultureInfo.InvariantCulture));
		dictionary.Add("cols", 20.ToString(CultureInfo.InvariantCulture));
		implicitRowsAndColumns = dictionary;
	}

	private static Dictionary<string, object> implicitRowsAndColumns;

	/// <summary>Returns a text input element for each property in the object that is represented by the specified expression.</summary>
	/// <returns>An HTML input element whose type attribute is set to "text" for each property in the object that is represented by the expression.</returns>
	/// <param name="htmlHelper">The HTML helper instance that this method extends.</param>
	/// <param name="expression">An expression that identifies the object that contains the properties to render.</param>
	/// <typeparam name="TModel">The type of the model.</typeparam>
	/// <typeparam name="TProperty">The type of the value.</typeparam>
	/// <exception cref="T:System.ArgumentException">The <paramref name="expression"/> parameter is null or empty.</exception>
	/// <created author="laurentiu.macovei" date="Tue, 12 Apr 2011 02:16:48 GMT"/>
	public static MvcHtmlString TextBoxForHtml<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
	{
		return htmlHelper.TextBoxForHtml<TModel, TProperty>(expression, ((IDictionary<string, object>)null));
	}

	/// <summary>Returns a text input element for each property in the object that is represented by the specified expression, using the specified HTML attributes.</summary>
	/// <returns>An HTML input element type attribute is set to "text" for each property in the object that is represented by the expression.</returns>
	/// <param name="htmlHelper">The HTML helper instance that this method extends.</param>
	/// <param name="expression">An expression that identifies the object that contains the properties to render.</param>
	/// <param name="htmlAttributes">A dictionary that contains the HTML attributes to set for the element.</param>
	/// <typeparam name="TModel">The type of the model.</typeparam>
	/// <typeparam name="TProperty">The type of the value.</typeparam>
	/// <exception cref="T:System.ArgumentException">The <paramref name="expression"/> parameter is null or empty.</exception>
	/// <created author="laurentiu.macovei" date="Tue, 12 Apr 2011 02:16:48 GMT"/>
	public static MvcHtmlString TextBoxForHtml<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IDictionary<string, object> htmlAttributes)
	{
		ModelMetadata metadata = ModelMetadata.FromLambdaExpression<TModel, TProperty>(expression, htmlHelper.ViewData);
		return htmlHelper.TextBoxHelperHtml(metadata, metadata.Model, ExpressionHelper.GetExpressionText(expression), htmlAttributes);
	}
	/// <summary>Returns a text input element for each property in the object that is represented by the specified expression, using the specified HTML attributes.</summary>
	/// <returns>An HTML input element whose type attribute is set to "text" for each property in the object that is represented by the expression.</returns>
	/// <param name="htmlHelper">The HTML helper instance that this method extends.</param>
	/// <param name="expression">An expression that identifies the object that contains the properties to render.</param>
	/// <param name="htmlAttributes">An object that contains the HTML attributes to set for the element.</param>
	/// <typeparam name="TModel">The type of the model.</typeparam>
	/// <typeparam name="TProperty">The type of the value.</typeparam>
	/// <exception cref="T:System.ArgumentException">The <paramref name="expression"/> parameter is null or empty.</exception>
	/// <created author="laurentiu.macovei" date="Tue, 12 Apr 2011 02:16:48 GMT"/>
	public static MvcHtmlString TextBoxForHtml<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes)
	{
		return htmlHelper.TextBoxForHtml<TModel, TProperty>(expression, ((IDictionary<string, object>)HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes)));
	}

	/// <summary>Returns a text input element for each property in the object that is represented by the specified expression, using the specified HTML attributes.</summary>
	/// <returns>An HTML input element whose type attribute is set to "text" for each property in the object that is represented by the expression.</returns>
	/// <param name="htmlHelper">The HTML helper instance that this method extends.</param>
	/// <param name="expression">An expression that identifies the object that contains the properties to render.</param>
	/// <param name="htmlAttributes">An object that contains the HTML attributes to set for the element.</param>
	/// <param name="metadata"></param>
	/// <param name="model"></param>
	/// <exception cref="T:System.ArgumentException">The <paramref name="expression"/> parameter is null or empty.</exception>
	/// <created author="laurentiu.macovei" date="Tue, 12 Apr 2011 02:16:48 GMT"/>
	private static MvcHtmlString TextBoxHelperHtml(this HtmlHelper htmlHelper, ModelMetadata metadata, object model, string expression, IDictionary<string, object> htmlAttributes)
	{
		if (model is string)
			model = HttpUtility.HtmlDecode(model as string);
		return InputHelper(htmlHelper, InputType.Text, metadata, expression, model, false, false, true, true, htmlAttributes);
	}
	private static readonly InputDataDelagete InputHelper = typeof(InputExtensions).GetStaticInvoker<InputDataDelagete>("InputHelper");
	/// <summary>The InputDataDelagete event handler</summary>
	/// <created author="laurentiu.macovei" date="Tue, 12 Apr 2011 02:16:49 GMT"/>
	private delegate MvcHtmlString InputDataDelagete(HtmlHelper htmlHelper, InputType inputType, ModelMetadata metadata, string name, object value, bool useViewData, bool isChecked, bool setId, bool isExplicitValue, IDictionary<string, object> htmlAttributes);

	/// <summary>Formats a timespan as a readable string i.e days, hours, minutes, seconds - whatever is important</summary>
	/// <param name="span">The timespan to render</param>
	/// <created author="laurentiu.macovei" date="Fri, 15 Apr 2011 00:39:49 GMT"/>
	public static string ToReadableString(this TimeSpan span)
	{
		string formatted = string.Format("{0}{1}{2}{3}",
			span.Days != 0 ? string.Format("{0:0} days, ", span.Days) : string.Empty,
			span.Hours != 0 ? string.Format("{0:0} hours, ", span.Hours) : string.Empty,
			span.Minutes != 0 ? string.Format("{0:0} mins, ", span.Minutes) : string.Empty,
			span.Seconds != 0 ? string.Format("{0:0} secs", span.Seconds) : string.Empty);

		if (formatted.EndsWith(", ")) formatted = formatted.Substring(0, formatted.Length - 2);

		return formatted;
	}

	/// <summary> Indicates whether the specified string is null or an System.String.Empty string. </summary>
	/// <param name="value">The string to test.</param>
	/// <returns>true if the value parameter is null or an empty string (""); otherwise, false</returns>
	/// <created author="laurentiu.macovei" date="Tue, 19 Apr 2011 15:30:51 GMT"/>
	public static bool IsNullOrEmpty(this string value)
	{
		return string.IsNullOrEmpty(value);
	}
	/// <summary> Indicates whether a specified string is null, empty, or consists only of white-space characters. </summary>
	/// <param name="value">The string to test.</param>
	/// <returns>true if the value parameter is null or System.String.Empty, or if value consists exclusively of white-space characters.</returns>
	/// <created author="laurentiu.macovei" date="Tue, 19 Apr 2011 15:30:51 GMT"/>
	public static bool IsNullOrWhiteSpace(this string value)
	{
		return string.IsNullOrWhiteSpace(value);
	}

	/// <summary>Returns markup that is not HTML encoded.</summary>
	/// <param name="html">The html helper to be extended</param>
	/// <param name="htmlFunc">The html </param>
	/// <returns></returns>
	/// <created author="laurentiu.macovei" date="Thu, 05 Jan 2012 23:02:37 GMT"/>
	public static IHtmlString Raw(this HtmlHelper html, Func<object, HelperResult> htmlFunc)
	{
		return html.Raw(htmlFunc(_o).ToHtmlString());
	}

	/// <summary>
	/// </summary>
	/// <param name="html"></param>
	/// <param name="partialViewName"></param>
	/// <param name="model"></param>
	/// <param name="bag"></param>
	/// <param name="updateMainBag"></param>
	/// <param name="forwardBag"></param>
	/// <returns></returns>
	/// <created author="laurentiu.macovei" date="Fri, 06 Jan 2012 00:11:04 GMT"/>
	public static MvcHtmlString Partial(this HtmlHelper html, string partialViewName, object model = null, object bag = null, bool updateMainBag = true, bool forwardBag = true)
	{
		var newBag = new ViewDataDictionary();
		var originalBag = html.ViewContext.ViewData;
		if (forwardBag)
			foreach (var item in originalBag)
				newBag.Add(item);
		if (bag != null)
		{
			var dic = new RouteValueDictionary(bag);
			foreach (var item in dic)
				newBag[item.Key] = item.Value;
		}
		var htmlResult = PartialExtensions.Partial(html, partialViewName, model, newBag);
		if (updateMainBag)
			foreach (var item in newBag)
				originalBag[item.Key] = newBag[item.Key];
		return htmlResult;
	}
	///// <summary>
	///// </summary>
	///// <param name="html"></param>
	///// <param name="partialViewName"></param>
	///// <param name="model"></param>
	///// <param name="bag"></param>
	///// <param name="updateMainBag"></param>
	///// <param name="forwardBag"></param>
	///// <returns></returns>
	///// <created author="laurentiu.macovei" date="Fri, 06 Jan 2012 00:11:04 GMT"/>
	//public static MvcHtmlString Partial(this HtmlHelper html, string partialViewName, dynamic model = default(dynamic), object bag = null, bool updateMainBag = true, bool forwardBag = true)
	//{
	//    var newBag = new ViewDataDictionary();
	//    var originalBag = html.ViewContext.ViewData;
	//    if (forwardBag)
	//        foreach (var item in originalBag)
	//        newBag.Add(item);
	//    if (bag != null)
	//    {
	//        var dic = new RouteValueDictionary(bag);
	//        foreach (var item in dic)
	//            newBag[item.Key] = item.Value;
	//    }
	//    var htmlResult = PartialExtensions.Partial(html, partialViewName, (object)model, newBag);
	//    if (updateMainBag)
	//        foreach (var item in newBag)
	//            originalBag[item.Key] = newBag[item.Key];
	//    return htmlResult;
	//}
	#endregion Business Methods


	#region DependentSection Class
	/// <summary>The DependentSection class</summary>
	/// <created author="laurentiu.macovei" date="Fri, 18 Mar 2011 02:23:33 GMT"/>
	public class DependentSection
	{

		#region Properties

		/// <summary>Gets or sets the Name</summary>
		/// <created author="laurentiu.macovei" date="Fri, 18 Mar 2011 02:23:33 GMT"/>
		public string Name { get; set; }

		/// <summary>Gets or sets the DefaultContent</summary>
		/// <created author="laurentiu.macovei" date="Fri, 18 Mar 2011 02:23:33 GMT"/>
		public Func<object, HelperResult> DefaultContent { get; set; }

		/// <summary>Gets or sets the Dependinces</summary>
		/// <created author="laurentiu.macovei" date="Fri, 18 Mar 2011 02:23:33 GMT"/>
		public DependentSection[] Dependinces { get; set; }


		#endregion Properties


		#region Business Methods

		/// <summary>
		/// </summary>
		/// <param name="page"></param>
		/// <param name="previousWriters"></param>
		/// <created author="laurentiu.macovei" date="Fri, 18 Mar 2011 02:23:33 GMT"/>
		internal void DefineDefaults(WebPageBase page, Dictionary<string, SectionWriter>[] previousWriters)
		{
			foreach (var previousWriter in previousWriters)
			{
				if (!previousWriter.ContainsKey(Name))
				//if (!page.IsSectionDefined(Name))
				{
					if (Dependinces != null && Dependinces.Length > 0)
						foreach (var section in Dependinces)
							section.DefineDefaults(page, previousWriters);
					previousWriter[Name] = () => page.Write(DefaultContent(_o));
					//page.DefineSection(Name, () => page.Write(DefaultContent(_o)));
				}
			}
		}


		#endregion Business Methods


	}
	#endregion Class  DependentSection
}
